<?php

/*
  function: 支付宝当面付模型

  create by: 王加明
  create date: 2017.2.27
  description:
  versions: v1.0

  modification 0.0.3
  modified by:
  description:
 */
/*
 * barpay($data)扫码当面付
 * qrpay扫二维码支付
 * query 支付订单检查
 * refund 已支付订单退款
 * 2017/1/10:修改方法名，全部方法名在前面加上下划线‘_’，用于防止和继承的payModel方法发生同名冲突。修改barpay返回参数。
 */

namespace app\common\model;
use think\Model;
class Alipay extends Pay
{
    var $config = [];
    public function __construct()
    {
        $this->config = config('alipay');
        $this->config['gatewayUrl'] = "https://openapi.alipay.com/gateway.do";//支付宝网管
        $this->config['MaxQueryRetry']="10";
        $this->config['charset'] ="UTF-8";
        $this->config['QueryDuration'] = "3";
        $this->config['sign_type'] = "RSA";
    }
    private function object2array(&$object) {
        $object = json_decode(json_encode($object), true);
        return $object;
    }
    //当面付扫条码支付
    /**
     * @param $data
     * @return array|void
     */
    protected function _barpay($data) {
        //导入
        vendor('AliPay.f2fpay.model.builder.AlipayTradePayContentBuilder');
        vendor('AliPay.f2fpay.service.AlipayTradeService');
        $outTradeNo = $data['order_id']; //订单号,通过订单号获取订单其他信息
        //判断订单号
        if (empty($outTradeNo) && trim($outTradeNo) == "") {
            return array('state' => 0, 'errormsg' => 'need order_id');
        }
        $totalAmount = $data['total_fee'] / 100; //把传入的分位数转换为单位为元
        // (必填) 付款条码
        $authCode = $data['auth_code'];
        $sellerId = '';
        //通过判断auth_code是否是支付宝标准的一个开头数字为28开头的18位一段数字
        if (substr($authCode, 0, 2) != 28 && strlen(floor($authCode)) != 18) {
            return array('state' => 0, 'errormsg' => 'authcode error');
        }
        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        //如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        //订单标题
          $subject = $body = $data['body'];
        //操作员编号
        //$operatorId = $data['operatorId'];
        //$alipayStoreId = $data['alipayStoreId'];
        //业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        $providerId = ""; //系统商pid,作为系统商返佣数据提取的依据
        $extendParams = new \ExtendParams();
        $extendParams->setSysServiceProviderId($providerId);
        $extendParamsArr = $extendParams->getExtendParams();
        // 支付超时，线下扫码交易定义为1分钟
        $timeExpress = "1m";
        //以上为订单信息采集-----------------------------------------------------------------------------12.23xu
        // 创建请求builder，设置请求参数
        $barPayRequestBuilder = new \AlipayTradePayContentBuilder();
        $barPayRequestBuilder->setOutTradeNo($outTradeNo);
        $barPayRequestBuilder->setTotalAmount($totalAmount);
        $barPayRequestBuilder->setAuthCode($authCode);
        $barPayRequestBuilder->setTimeExpress($timeExpress);
        $barPayRequestBuilder->setSubject($subject);
        $barPayRequestBuilder->setBody($body);
        //$barPayRequestBuilder->setUndiscountableAmount($undiscountableAmount);
        $barPayRequestBuilder->setExtendParams($extendParamsArr);
        //$barPayRequestBuilder->setGoodsDetailList($goodsDetailList);
        //$barPayRequestBuilder->setStoreId($storeId);
        //$barPayRequestBuilder->setOperatorId($operatorId);
        //$barPayRequestBuilder->setAlipayStoreId($alipayStoreId);
        //$barPayRequestBuilder->setAppAuthToken($appAuthToken);
        //调用barPay方法获取当面付应答
        $barPay = new \AlipayTradeService($this->config);//$config
        $barPayResult = $barPay->barPay($barPayRequestBuilder);
        //把支付宝返回值转换为array形式然后取出
        $object = $barPayResult;
        if (is_object($object)) {
            $arr = (array) ($object);
        } else {
            $arr = &$object;
        }
        if (is_array($arr)) {
            foreach ($arr as $varName => $varValue) {
                $arr[$varName] = $this->object2array($varValue);
            }
        }
        foreach ($arr as $key => $value) {
            $response = $value;
        }
        switch ($barPayResult->getTradeStatus()) {
            case "SUCCESS":
                return array('state' => 1, 'errormsg' => 'Transaction successful', 'data' => array('order_id' => $outTradeNo, 'total_fee' => bcadd($totalAmount * 100)));
                break;
            case "FAILED":
                //在返回失败时再走query检查一下订单状态，
                $query = $this->_query($outTradeNo);
                $arr = [
                    'state' => $query['state'], 'errormsg' => $response['code'], 'data' => $response
                ];
                return $arr;
                break;
            case "UNKNOWN":
                //在返回失败时再走query检查一下订单状态，
                $query = $this->_query($outTradeNo);
                return array('state' => $query['state'], 'errormsg '=> $response['code'], 'data' => $response);
                break;
            default:
                return array('state' => 0, 'errormsg' => 'Abnormal trading');
                break;
        }
        return;
    }
    //当面付扫二维码支付
    protected function _qrpay($data){
        //导入
        vendor('AliPay.f2fpay.model.builder.AlipayTradePrecreateContentBuilder');
        vendor('AliPay.f2fpay.service.AlipayTradeService');
        $outTradeNo = $data['order_id']; //订单号,通过订单号获取订单其他信息
        //判断订单号
        if (empty($outTradeNo) && trim($outTradeNo) == "") {
            return array('state' => 0, 'errormsg' => 'need order_id');
        }
        $totalAmount = $data['total_fee'] / 100; //把传入的分位数转换为单位为元
        $sellerId = '';
        $subject = $body = $data['body'];
        //$operatorId = $data['operatorId'];
        $providerId = ""; //系统商pid,作为系统商返佣数据提取的依据
        $extendParams = new \ExtendParams();
        $extendParams->setSysServiceProviderId($providerId);
        $extendParamsArr = $extendParams->getExtendParams();
        $timeExpress = "1m";
        $qrPayRequestBuilder = new \AlipayTradePrecreateContentBuilder();
        $qrPayRequestBuilder->setOutTradeNo($outTradeNo);
        $qrPayRequestBuilder->setTotalAmount($totalAmount);
        $qrPayRequestBuilder->setTimeExpress($timeExpress);
        $qrPayRequestBuilder->setSubject($subject);
        $qrPayRequestBuilder->setBody($body);
        //$barPayRequestBuilder->setUndiscountableAmount($undiscountableAmount);
        $qrPayRequestBuilder->setExtendParams($extendParamsArr);
        //$qrPayRequestBuilder->setGoodsDetailList($goodsDetailList);
        //$qrPayRequestBuilder->setStoreId($storeId);
        // $qrPayRequestBuilder->setOperatorId($operatorId);
        //$qrPayRequestBuilderr->setAlipayStoreId($alipayStoreId);
        // $barPayRequestBuilder->setAppAuthToken($appAuthToken);
        // 调用qrPay方法获取当面付应答
        $qrPay = new \AlipayTradeService($this->config);
        $qrPayResult = $qrPay->qrPay($qrPayRequestBuilder);
        //	根据状态值进行业务处理
        switch ($qrPayResult->getTradeStatus()){
            case "SUCCESS":
                //echo "支付宝创建订单二维码成功:"."<br>---------------------------------------<br>";
                $response = $qrPayResult->getResponse();
                $state['code']=$response->qr_code;
                return array('state'=>1,'data'=>$state);
                break;
            case "FAILED":
                //echo "系统异常，状态未知!!!"."<br>--------------------------<br>";
                if(!empty($qrPayResult->getResponse())){
                    print_r($qrPayResult->getResponse());
                }
                break;
            case "UNKNOWN":
                //echo "系统异常，状态未知!!!"."<br>--------------------------<br>";
                if(!empty($qrPayResult->getResponse())){
                    print_r($qrPayResult->getResponse());
                }
                break;
            default:
                //echo "不支持的返回状态，创建订单二维码返回异常!!!";
                return array('state' => 0, 'errormsg' => 'Abnormal trading');
                break;
        }
        return ;
    }
    //交易检查
    protected function _query($out_trade_no) {
        vendor('AliPay.f2fpay.service.AlipayTradeService');
        //第三方应用授权令牌,商户授权系统商开发模式下使用
        $appAuthToken = ""; //根据真实值填写
        //构造查询业务请求参数对象
        $queryContentBuilder = new \AlipayTradeQueryContentBuilder();
        $queryContentBuilder->setOutTradeNo($out_trade_no);
        $queryContentBuilder->setAppAuthToken($appAuthToken);
        //初始化类对象，调用queryTradeResult方法获取查询应答
        $queryResponse = new \AlipayTradeService($this->config);
        $queryResult = $queryResponse->queryTradeResult($queryContentBuilder);
        //根据查询返回结果状态进行业务处理
        $state = json_decode(json_encode($queryResult->getResponse()), TRUE);
        $state['order_id'] = $out_trade_no;
        $state['channel'] = 'BARPAY';
        switch ($queryResult->getTradeStatus()) {
            case "SUCCESS":
                $state['total_fee'] = (int) ($state['total_amount']*100);
                return array('state' => 1, 'errormsg' => $state['code'], 'data' => $state);
                break;
            case "FAILED":
                return array('state' => 0, 'errormsg' => $state['code'], 'data' => $state);
                break;
            case "UNKNOWN":
                return array('state' => 0, 'errormsg' => $state['code'], 'data' => $state);
                break;
            default:
                return array('state' => 0, 'errormsg' => $state['code']);
                //echo "不支持的查询状态，交易返回异常!!!";
                break;
        }
        return;
    }
    //退款
    protected function _refund($data) {
        vendor('AliPay.f2fpay.service.AlipayTradeService');
        vendor('AliPay.f2fpay.model.builder.AlipayTradeRefundContentBuilder');
        $out_trade_no = $data['order_id'];//订单号
        $refund_amount = $data['refund_fee']; //需要退款的金额
        //之前退款的总金额
        if(!isset($data['refund_total_fee'])){
            return ['state'=>0,'errormsg'=>'退款金额为空'];
        }
        $refund_total_fee = $data['refund_total_fee'];
        // $out_request_no = $data[out_request_no];//test退款流水号
        //先refund_qurey($out_trade_no_0,1,2,3,4)直到流水号查不到退款记录，那么这时流水号就是$out_trade_no.'_$num'
        //假设有100次退款记录
        // $refund_total_fee_alipay = '';
        $refund_total_fee_alipay =array();
        for ($i = 0; $i <= 100; $i++) {
            $queryinfo = $this->_refund_query($out_trade_no.'_'.$i, $out_trade_no,$this->config);
            //已退款金额（支付宝系统核对）
            if(isset($queryinfo['data']['refund_amount'])){
               $refund_total_fee_alipay[$i] = $queryinfo['data']['refund_amount'];
            }
            //查到第$i次没有退款记录，那么就可以判断这次的退款是第$i次，则这次退款流水号就是$out_trade_no."_".$i
            if (isset($queryinfo['state']) && $queryinfo['state']) {
                $out_request_no = $out_trade_no."_".$i;
                break;
            }
        }
        $refund_total_fee_alipay = array_sum($refund_total_fee_alipay)*100;
        //数据库未存金额
        $refund_unsave = $refund_total_fee_alipay - $refund_total_fee;
        if ($refund_amount <= $refund_unsave) {
            return array('state' => 1,'refund' =>$refund_unsave);
        }
        //系统传的退款金额-数据库未存金额
        $refund_fee_continue = $refund_amount - $refund_unsave;
        $refund_fee_input = $refund_fee_continue?$refund_fee_continue:$refund_amount;
        //第三方应用授权令牌,商户授权系统商开发模式下使用
        //$appAuthToken = ""; //根据真实值填写
        //创建退款请求builder,设置参数
        $refundRequestBuilder = new \AlipayTradeRefundContentBuilder();
        $refundRequestBuilder->setOutTradeNo($out_trade_no);
        $refundRequestBuilder->setRefundAmount($refund_fee_input / 100);
        $refundRequestBuilder->setOutRequestNo($out_request_no);
        //$refundRequestBuilder->setAppAuthToken($appAuthToken);
        //初始化类对象,调用refund获取退款应答
        $refundResponse = new \AlipayTradeService($this->config);
        $refundResult = $refundResponse->refund($refundRequestBuilder);
        //把支付宝返回值转换为array形式然后取出
        $object = $refundResult;
        if (is_object($object)) {
            $arr = (array) ($object);
        } else {
            $arr = &$object;
        }
        if (is_array($arr)) {
            foreach ($arr as $varName => $varValue) {
                $arr[$varName] = $this->object2array($varValue);
            }
        }
        foreach ($arr as $key => $value) {
            $response = $value;
        }
        $state = $response;
        $state['order_id'] = $out_trade_no;
        //$state[out_request_no] = $out_request_no;
        //$state[channel] = 'BARPAY';
        //根据交易状态进行处理
        switch ($refundResult->getTradeStatus()) {
            case "SUCCESS";
                //model('Action')->add('refund Alipay',$out_trade_no,'fail',$refund_fee);
                //成功
                $state['refund_fee'] = (int) ($refund_amount);
                return array('state' => 1, 'errormsg' => $state['code'], 'data' => $state, 'refund' => $state['refund_fee']);
                break;
            case "FAILED":
                //失败
                $state['refund_fee'] = (int) ($refund_unsave);
                return array('state' => 0, 'errormsg' => $state['code'], 'data' => $state, 'refund' => $state['refund_fee']);
                break;
            case "UNKNOWN":
                $state['refund_fee'] = (int) ($refund_unsave);
                return array('state' => 0, 'errormsg' => $state['code'], 'data' => $state, 'refund' => $state['refund_fee']);
                break;
            default:
                $state['refund_fee'] = (int)($refund_unsave);
                return array('state' => 0, 'errormsg' => $state['code'], 'data' => $state, 'refund' => $state['refund_fee']);
                //echo "不支持的交易状态，交易返回异常!!!";
                break;
        }
        return;
    }
    //退款查询
    protected function _refund_query($out_request_no, $out_trade_no,$config)
    {
        //导入
        if (!$config) {
            vendor('AliPay.f2fpay.service.AlipayTradeService');
        }
        $aop = new \AopClient();
        $aop->gatewayUrl = $config['gatewayUrl'];
        $aop->appId = $config['app_id'];
        $aop->rsaPrivateKey = $config['merchant_private_key'];
        $aop->alipayrsaPublicKey = $config['alipay_public_key'];
        $aop->apiVersion = '1.0';
        $aop->signType = 'RSA';
        $aop->postCharset = 'UTF-8';
        $aop->format = 'json';
        $request = new \AlipayTradeFastpayRefundQueryRequest();
        $request->setBizContent("{" .
            "    \"trade_no\":\"\"," .
            "    \"out_trade_no\":\"$out_trade_no\"," .
            "    \"out_request_no\":\"$out_request_no\"" .
            "  }");
        $result = $aop->execute($request);
        $res = json_decode(json_encode($result), 1)['alipay_trade_fastpay_refund_query_response'];
        if (isset($res['out_request_no'])) {
            $state = 0;
        } else {
            $state = 1;
        }
        return array('state' => $state, 'data' => $res);
    }
    //回调
    function comeback(){
        vendor('AliPayWap.wappay.service.AlipayTradeService');
        $arr=$_POST;
        $alipaySevice = new \AlipayTradeService($this->config);
        $alipaySevice->writeLog(var_export($_POST,true));
        $result = $alipaySevice->check($arr);
        if($result) {
            //验证成功
            //商户订单号
            $out_trade_no = $_POST['out_trade_no'];
            //支付宝交易号
            $trade_no = $_POST['trade_no'];
            //交易状态
            $trade_status = $_POST['trade_status'];
            if($_POST['trade_status'] == 'TRADE_FINISHED') {
            }
            else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
            }
//            echo "success";		//请不要修改或删除
            return array('state'=>1,'data'=>$arr);

        }else {
            //验证失败

//            echo "fail";	//请不要修改或删除
            return array('state'=>0,'message'=>false);
        }
    }
    /*
     * 查询对账单
     * $data 日期
     * $code 编码
     * */
    function download($data){
        vendor('AliPay.f2fpay.service.AlipayTradeService');
        //处理参数
        $start = strtotime($data['start']);
        $end = strtotime($data['end']);
        if($start == $end){
            $date = date('Y-m-d',$start);
        }else{
            $date = date('Y-m',$start);
        }
        $aop = new \AopClient ();
        $aop->gatewayUrl = $this->config['gatewayUrl'];
        $aop->appId = $this->config['app_id'];
        $aop->rsaPrivateKey = $this->config['merchant_private_key'];
        $aop->alipayrsaPublicKey=$this->config['alipay_public_key'];;
        $aop->apiVersion = '1.0';
        $aop->signType = 'RSA';
        $aop->postCharset='utf-8';
        $aop->format='json';
        $request = new \AlipayDataDataserviceBillDownloadurlQueryRequest ();
        $request->setBizContent("{" .
            "    \"bill_type\":\"trade\"," .
            "    \"bill_date\":\"$date\"" .
            "  }");
        $result = $aop->execute ( $request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $resultCode = $result->$responseNode->code;
        if(!empty($resultCode)&&$resultCode == 10000){
            echo "成功";
            $res = $result->alipay_data_dataservice_bill_downloadurl_query_response->bill_download_url;
            return array('state'=>1,'url'=>$res);
        } else {
            echo "查询日期无账单，请选择其他日期";
            /*return array('state'=>0,'errormsg'=>"");*/
        }
    }
    //手机app支付
    function wap_pay($data){
        vendor('AliPayWap.wappay.service.AlipayTradeService');
        vendor('AliPayWap.wappay.buildermodel.AlipayTradeWapPayContentBuilder');
        //商户订单号，商户网站订单系统中唯一订单号，必填
        $out_trade_no = $data['order_id'];

        //订单名称，必填
        $subject = $data['body'];

        //付款金额，必填
        $total_amount = $data['price'];

        //超时时间
        $timeout_express="1m";
        $payRequestBuilder = new \AlipayTradeWapPayContentBuilder();
        //$payRequestBuilder->setBody($body);
        $payRequestBuilder->setSubject($subject);
        $payRequestBuilder->setOutTradeNo($out_trade_no);
        $payRequestBuilder->setTotalAmount($total_amount);
        $payRequestBuilder->setTimeExpress($timeout_express);

        $payResponse = new \AlipayTradeService($this->config);
        $result=$payResponse->wapPay($payRequestBuilder,$this->config['return_url'],$this->config['notify_url']);
        if($result){
            $res['state'] = 1;
            $res['data']['url'] = $result;
        }else{
            return $result;
        }
//        dump($result);die;
        return  $res;
    }
    //手机支付查询
    function wap_query($data){
       vendor('AliPay.wappay.service.AlipayTradeService');
       vendor('AliPay.wappay.buildermodel.AlipayTradeQueryContentBuilder');
        //商户订单号和支付宝交易号不能同时为空。 trade_no、  out_trade_no如果同时存在优先取trade_no
        //商户订单号，和支付宝交易号二选一
        $out_trade_no = trim($data['WIDout_trade_no']);

        /*//支付宝交易号，和商户订单号二选一
        $trade_no = trim($data['WIDtrade_no']);*/

        $RequestBuilder = new AlipayTradeQueryContentBuilder();
        //$RequestBuilder->setTradeNo($trade_no);
        $RequestBuilder->setOutTradeNo($out_trade_no);

        $Response = new AlipayTradeService($this->config);
        $result=$Response->Query($RequestBuilder);
        return ;
    }
    //手机支付退款
    function wap_refund($data){
        vendor('AliPay.wappay.service.AlipayTradeService');
        vendor('AliPay.wappay.buildermodel.AlipayTradeQueryContentBuilder');
        //商户订单号和支付宝交易号不能同时为空。 trade_no、  out_trade_no如果同时存在优先取trade_no
        //商户订单号，和支付宝交易号二选一
        $out_trade_no = trim($data['WIDout_trade_no']);

        //支付宝交易号，和商户订单号二选一
        $trade_no = trim($data['WIDtrade_no']);

        //退款金额，不能大于订单总金额
        $refund_amount=trim($data['WIDrefund_amount']);

        //退款的原因说明
        $refund_reason=trim($data['WIDrefund_reason']);

        //标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
        $out_request_no=trim($data['WIDout_request_no']);

        $RequestBuilder = new AlipayTradeRefundContentBuilder();
        $RequestBuilder->setTradeNo($trade_no);
        $RequestBuilder->setOutTradeNo($out_trade_no);
        $RequestBuilder->setRefundAmount($refund_amount);
        $RequestBuilder->setRefundReason($refund_reason);
        $RequestBuilder->setOutRequestNo($out_request_no);

        $Response = new AlipayTradeService($this->config);
        $result=$Response->Refund($RequestBuilder);
        return ;
    }
    //手机退款查询
    function wap_refundquery(){

    }
    function test($data){
        $res = $this->wap_pay($data);
//        $res = $this->_qrpay($data);
        return $res;
    }
}
